import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedList;

public class LFSR {

	//public static int pozicija = 12;
	
	public static LinkedList<Integer> functionArguments=new LinkedList<Integer>();
	
	LinkedList<Integer> lfsr = new LinkedList<Integer>();

	// LinkedList<Integer> polinom=new LinkedList<Integer>();
	LinkedList<Polinom> polinomList = new LinkedList<Polinom>();

	int dolzina = 12;

	public LFSR() {

		lfsr.add(0);
		lfsr.add(0);
		lfsr.add(0);
		lfsr.add(0);
		lfsr.add(0);
		lfsr.add(0);
		lfsr.add(0);
		lfsr.add(0);
		lfsr.add(0);
		lfsr.add(0);
		lfsr.add(0);
		lfsr.add(0);
		
		functionArguments.add(0);
		functionArguments.add(3);
		functionArguments.add(6);
		functionArguments.add(9);
		functionArguments.add(10);
		functionArguments.add(11);
	}

	public String toString() {

		return this.lfsr.toString();

	}

	// presmetka za dolzina na lfsr-to
	public void setDolzina() {
		this.dolzina = 6;
	}

	public LinkedList<Polinom> getPolinom(String fileName) throws IOException {

		// LinkedList<Polinom> polinomList=new LinkedList<Polinom>();
		BufferedReader read = new BufferedReader(new FileReader(fileName));
		Polinom tmp;
		String r;

		while ((r = read.readLine()) != null) {

			// pomosna promenliva za vnesuvanje na polinomite
			tmp = new Polinom();
			// vnesi ja kvazigrupata
			tmp.setQuasigroup(Integer.parseInt(r));
			tmp.setPolinomi(read.readLine());
			tmp.setPolinomi(read.readLine());
			tmp.setPolinomi(read.readLine());

			this.polinomList.add(tmp);
		}

		read.close();
		return polinomList;
	}

	public String generateLfsr(String polinom1, String polinom2, String polinom3) {

		int bit_feedback1, bit_feedback2, bit_feedback3;

		String[] pomPolinom1 = polinom1.split("\\+");
	
		String[] pomPolinom2 = polinom2.split("\\+");
		
		String[] pomPolinom3 = polinom3.split("\\+");
		
		/*
		 * ----------------------- Inicijaliziranje na bit_feedback
		 * --------------------------
		 */
		bit_feedback1 = evaluatePolynomial(pomPolinom1);
		bit_feedback2 = evaluatePolynomial(pomPolinom2);
		bit_feedback3 = evaluatePolynomial(pomPolinom3);

//		int countZERO = 0;
//		int countONE = 0;
		
		
		//posledni 3
		/*if(lfsr.get(9)==0)
		{
			countZERO++;
		}
		else
		{
			countONE++;
		}
		
		if(lfsr.get(10)==0)
		{
			countZERO++;
		}
		else
		{
			countONE++;
		}
		
		if(lfsr.get(11)==0)
		{
			countZERO++;
		}
		else
		{
			countONE++;
		}*/
	
		//max so shiftanje
		/*if(lfsr.get(LFSR.pozicija-3)==0)
		{
			countZERO++;
		}
		else
		{
			countONE++;
		}
		
		if(lfsr.get(LFSR.pozicija-2)==0)
		{
			countZERO++;
		}
		else
		{
			countONE++;
		}
		
		if(lfsr.get(LFSR.pozicija-1)==0)
		{
			countZERO++;
		}
		else
		{
			countONE++;
		}
*/		
		
		
		String bitS = String.valueOf(lfsr.getLast());
		this.lfsr.removeLast();

		bitS = String.valueOf(lfsr.getLast()) + bitS;
		this.lfsr.removeLast();

		bitS = String.valueOf(lfsr.getLast()) + bitS;
		this.lfsr.removeLast();
		
		/*if(bitS.charAt(0)=='0')
		{
			countZERO++;
		}
		else
		{
			countONE++;
		}
		
		if(bitS.charAt(1)=='0')
		{
			countZERO++;
		}
		else
		{
			countONE++;
		}
		
		if(bitS.charAt(2)=='0')
		{
			countZERO++;
		}
		else
		{
			countONE++;
		}*/
		
		//obichno
		this.lfsr.addFirst(bit_feedback3);
		this.lfsr.addFirst(bit_feedback2);
		this.lfsr.addFirst(bit_feedback1);
		
		
	/*	//za so max
		if(countZERO<countONE lfsr.get(5)==1)
		{
			this.lfsr.addFirst(bit_feedback3);
			this.lfsr.addFirst(bit_feedback2);
			this.lfsr.addFirst(bit_feedback1);
		}
		else
		{
			this.lfsr.addFirst(bit_feedback1);
			this.lfsr.addFirst(bit_feedback3);
			this.lfsr.addFirst(bit_feedback2);
		}
	*/	
		/*
		
		LFSR.pozicija--;
		if(LFSR.pozicija<3)
		{
			LFSR.pozicija=12;
		}*/
		
		
		return bitS;
	}

	
	// ************************* evaluate polynomial *********************
	public int evaluatePolynomial(String[] pomPolinom)
	{
		int bit_feedback,pomBit1,pozicija;
		String[] monom1;
		
			// ako imame 1 na pocetokot na polinomot
			if (pomPolinom[0].length() < 2) {
				bit_feedback = 1;
			}

			// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja od
			// 0)
			else if (pomPolinom[0].length() == 2) {
				pozicija = Integer.parseInt(pomPolinom[0].substring(1)) - 1;
				bit_feedback = this.lfsr.get(LFSR.functionArguments.get(pozicija));
			}

			// ako imame monom x1*x2*x3
			else {
				monom1 = pomPolinom[0].split("\\*");
				pozicija = Integer.parseInt(monom1[0].substring(1)) - 1;
				pomBit1 = this.lfsr.get(LFSR.functionArguments.get(pozicija));

				for (int i = 1; i < monom1.length; i++) {
					pozicija = Integer.parseInt(monom1[i].substring(1)) - 1;
					pomBit1 &= this.lfsr.get(LFSR.functionArguments.get(pozicija));
				}
				bit_feedback = pomBit1;
			}
			// System.out.println("fidback "+bit_feedback);

			for (int i = pomPolinom.length - 1; i > 0; i--) {

				// ako imame 1 na pocetokot na polinomot
				if (pomPolinom[i].length() < 2) {
					bit_feedback ^= 1;
				}
				// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja
				// od 0)
				else if (pomPolinom[i].length() == 2) {
					pozicija = Integer.parseInt(pomPolinom[i].substring(1)) - 1;
					bit_feedback ^= this.lfsr.get(LFSR.functionArguments.get(pozicija));
				}
				// ako imame monom x1*x2*x3
				else {

					monom1 = pomPolinom[i].split("\\*");
					pozicija = Integer.parseInt(monom1[0].substring(1)) - 1;
					pomBit1 = this.lfsr.get(LFSR.functionArguments.get(pozicija));

					for (int j = 1; j < monom1.length; j++) {
						pozicija = Integer.parseInt(monom1[j].substring(1)) - 1;
						pomBit1 &= this.lfsr.get(LFSR.functionArguments.get(pozicija));
					}
					bit_feedback ^= pomBit1;
				}

			}
			return bit_feedback;
	}
	
	public String binToHex(String convert) throws IOException {

		String hexa = "";

//		while (convert.length() % 8 != 0) {
//			convert += "0";
//		}
		int br = 0;

		for (int k = 0; k < convert.length();) {
			
			br++;
			int broj = Integer.parseInt(convert.substring(k, k + 4), 2);
			String hexString = Integer.toHexString(broj);
			System.out.println("tukaaa "+hexString);
			if (br == 80) {
				
				hexa+=hexString + "\n";
				br = 0;
			} else {
				hexa+=hexString;
			}
			k += 4;
//System.out.println("h: "+hexa);
		}
	//	out.close();
		return hexa;
	}

	public static void main(String[] args) throws InterruptedException,IOException {
		// tuka sekoj da si go napise imeto na svojata datoteka na polinomi
		String fileName = "polinomi.txt";

		// za generiranje na polinomi
		LFSR l = new LFSR();
		BufferedWriter file1;
		LFSR lfsr;
		LinkedList<Polinom> polinomList = new LinkedList<Polinom>();
		polinomList = l.getPolinom(fileName);

		// brojot na kvazigrupata
		// int quasi;
		LinkedList<String> polinomi;

		for (int i = 0; i < polinomList.size() ; i++) {
			System.out.println(i);
			lfsr = new LFSR();
			file1 = new BufferedWriter(new FileWriter("datoteki\\q"+ polinomList.get(i).getQuasigroup() + ".txt"));
			polinomi = polinomList.get(i).getPolinomi();
			String bit = "";

			for (int j = 0; j < 15000; j++) {

				 bit = lfsr.generateLfsr(polinomi.get(0), polinomi.get(1),polinomi.get(2));
				 file1.write(bit);
				 file1.flush();
			}
			polinomi.clear();
			// zatvoranje na site datoteki
			file1.close();

		}
	
	}
}


/*// ************************* POLINOM1 *********************
// ako imame 1 na pocetokot na polinomot
if (pomPolinom1[0].length() < 2) {
	bit_feedback1 = 1;
}

// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja od
// 0)
else if (pomPolinom1[0].length() == 2) {
	pozicija = Integer.parseInt(pomPolinom1[0].substring(1)) - 1;
	bit_feedback1 = this.lfsr.get(LFSR.functionArguments.get(pozicija));
}

// ako imame monom x1*x2*x3
else {
	monom1 = pomPolinom1[0].split("\\*");
	pozicija = Integer.parseInt(monom1[0].substring(1)) - 1;
	pomBit1 = this.lfsr.get(LFSR.functionArguments.get(pozicija));

	for (int i = 1; i < monom1.length; i++) {
		pozicija = Integer.parseInt(monom1[i].substring(1)) - 1;
		pomBit1 &= this.lfsr.get(LFSR.functionArguments.get(pozicija));
	}
	bit_feedback1 = pomBit1;
}
// System.out.println("fidback "+bit_feedback);

for (int i = pomPolinom1.length - 1; i > 0; i--) {

	// ako imame 1 na pocetokot na polinomot
	if (pomPolinom1[i].length() < 2) {
		bit_feedback1 ^= 1;
	}
	// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja
	// od 0)
	else if (pomPolinom1[i].length() == 2) {
		pozicija = Integer.parseInt(pomPolinom1[i].substring(1)) - 1;
		bit_feedback1 ^= this.lfsr.get(LFSR.functionArguments.get(pozicija));
	}
	// ako imame monom x1*x2*x3
	else {

		monom1 = pomPolinom1[i].split("\\*");
		pozicija = Integer.parseInt(monom1[0].substring(1)) - 1;
		pomBit1 = this.lfsr.get(LFSR.functionArguments.get(pozicija));

		for (int j = 1; j < monom1.length; j++) {
			pozicija = Integer.parseInt(monom1[j].substring(1)) - 1;
			pomBit1 &= this.lfsr.get(LFSR.functionArguments.get(pozicija));
		}
		bit_feedback1 ^= pomBit1;
	}

}

// ************************* POLINOM2 *********************
// ako imame 1 na pocetokot na polinomot
if (pomPolinom2[0].length() < 2) {
	bit_feedback2 = 1;
}

// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja od
// 0)
else if (pomPolinom2[0].length() == 2) {
	pozicija = Integer.parseInt(pomPolinom2[0].substring(1)) - 1;
	bit_feedback2 = this.lfsr.get(LFSR.functionArguments.get(pozicija));
}

// ako imame monom x1*x2*x3
else {
	monom2 = pomPolinom2[0].split("\\*");
	pozicija = Integer.parseInt(monom2[0].substring(1)) - 1;
	pomBit2 = this.lfsr.get(LFSR.functionArguments.get(pozicija));

	for (int i = 1; i < monom2.length; i++) {
		pozicija = Integer.parseInt(monom2[i].substring(1)) - 1;
		pomBit2 &= this.lfsr.get(LFSR.functionArguments.get(pozicija));
	}
	bit_feedback2 = pomBit2;
}
// System.out.println("fidback "+bit_feedback);

for (int i = pomPolinom2.length - 1; i > 0; i--) {

	// ako imame 1 na pocetokot na polinomot
	if (pomPolinom2[i].length() < 2) {
		bit_feedback2 ^= 1;
	}
	// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja
	// od 0)
	else if (pomPolinom2[i].length() == 2) {
		pozicija = Integer.parseInt(pomPolinom2[i].substring(1)) - 1;
		bit_feedback2 ^= this.lfsr.get(LFSR.functionArguments.get(pozicija));
	}
	// ako imame monom x1*x2*x3
	else {

		monom2 = pomPolinom2[i].split("\\*");
		pozicija = Integer.parseInt(monom2[0].substring(1)) - 1;
		pomBit2 = this.lfsr.get(LFSR.functionArguments.get(pozicija));

		for (int j = 1; j < monom2.length; j++) {
			pozicija = Integer.parseInt(monom2[j].substring(1)) - 1;
			pomBit2 &= this.lfsr.get(LFSR.functionArguments.get(pozicija));
		}
		bit_feedback2 ^= pomBit2;
	}

}

// ************************* POLINOM3 *********************
// ako imame 1 na pocetokot na polinomot
if (pomPolinom3[0].length() < 2) {
	bit_feedback3 = 1;
}

// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja od
// 0)
else if (pomPolinom3[0].length() == 2) {
	pozicija = Integer.parseInt(pomPolinom3[0].substring(1)) - 1;
	bit_feedback3 = this.lfsr.get(LFSR.functionArguments.get(pozicija));
}

// ako imame monom x1*x2*x3
else {
	monom3 = pomPolinom3[0].split("\\*");
	pozicija = Integer.parseInt(monom3[0].substring(1)) - 1;
	pomBit3 = this.lfsr.get(LFSR.functionArguments.get(pozicija));

	for (int i = 1; i < monom3.length; i++) {
		pozicija = Integer.parseInt(monom3[i].substring(1)) - 1;
		pomBit3 &= this.lfsr.get(LFSR.functionArguments.get(pozicija));
	}
	bit_feedback3 = pomBit3;
}
// System.out.println("fidback "+bit_feedback);

for (int i = pomPolinom3.length - 1; i > 0; i--) {

	// ako imame 1 na pocetokot na polinomot
	if (pomPolinom3[i].length() < 2) {
		bit_feedback3 ^= 1;
	}
	// ako monomot ni e x1 zapisuvame 0 (bidejki nizata na lfsr pocinja
	// od 0)
	else if (pomPolinom3[i].length() == 2) {
		pozicija = Integer.parseInt(pomPolinom3[i].substring(1)) - 1;
		bit_feedback3 ^= this.lfsr.get(LFSR.functionArguments.get(pozicija));
	}
	// ako imame monom x1*x2*x3
	else {

		monom3 = pomPolinom3[i].split("\\*");
		pozicija = Integer.parseInt(monom3[0].substring(1)) - 1;
		pomBit3 = this.lfsr.get(LFSR.functionArguments.get(pozicija));

		for (int j = 1; j < monom3.length; j++) {
			pozicija = Integer.parseInt(monom3[j].substring(1)) - 1;
			pomBit3 &= this.lfsr.get(LFSR.functionArguments.get(pozicija));
		}
		bit_feedback3 ^= pomBit3;
	}

}

//System.out.println("LFSR: "+lfsr.toString());
*/

